package com.hxtt.smartsearch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hxtt.smartsearch.dao.SmartSearchDao;
import com.hxtt.smartsearch.dto.*;
import com.hxtt.smartsearch.model.SmartSearchModel;
import com.hxtt.smartsearch.service.ISmartSearchService;
import com.hxtt.smartsearch.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author hxtt
 * @date 2024/01/24
 */
@Service("SmartSearchServiceImpl")
@Slf4j
public class SmartSearchServiceImpl implements ISmartSearchService {

    @Autowired
    @Qualifier("esClusterClient")
    private RestHighLevelClient esClusterClient;

    @Autowired
    private RestHighLevelClient esSingleClient;

    @Autowired
    private SmartSearchDao smartSearchDao;

    @Value("${customAttributes.index}")
    private String index;

    @Value("${customAttributes.fetchSources}")
    private String fetchSources;

    @Override
    public ResponseResultDto searchBySql(SmartSearchModel model) {
        if (model.getPageIndex() == null || model.getPageIndex() <= 0) {
            model.setPageIndex(1);
        }
        if (model.getPageSize() == null || model.getPageSize() <= 0) {
            model.setPageSize(10);
        }
        PageHelper.startPage(model.getPageIndex(), model.getPageSize());
        List<SmartSearchDto> smartSearchDtos = smartSearchDao.searchBySql(model);
        PageInfo<SmartSearchDto> pageInfo = new PageInfo<>(smartSearchDtos);
        ResponseResultDto responseDto = new ResponseResultDto();
        responseDto.setDatas(smartSearchDtos);
        responseDto.setTotal((double) pageInfo.getTotal());
        return responseDto;
    }

    @Override
    public ResponseResultDto searchByEs(SmartSearchModel model) {
        SearchRequest searchRequest = new SearchRequest(index);
        //构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // es 分页每页条数，默认15条
        Integer size = (model.getPageSize() == null || model.getPageSize() < 1) ? 15 : model.getPageSize();
        // es 分页起始行数，默认0行开始
        Integer from = (model.getPageIndex() == null || model.getPageIndex() <= 1) ? 0 : (model.getPageIndex() - 1) * size;
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);
        //设定希望返回的字段数组
        searchSourceBuilder.fetchSource(fetchSources.split(","), null);
        // 跟级bool查询
        BoolQueryBuilder bool0 = QueryBuilders.boolQuery();

        // 省市区等过滤bool查询
        BoolQueryBuilder bool1 = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(model.getCountyCode())) {
            bool1.must(QueryBuilders.termQuery("county_id_short", model.getCountyCode()));
            bool0.must(bool1);
        }

        // 名称、拼音、简拼、地址条件查询
        BoolQueryBuilder bool2 = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(model.getKeyword())) {
            bool2.should(QueryBuilders.multiMatchQuery(model.getKeyword(), "name").analyzer("ik_smart"));
            bool2.should(QueryBuilders.multiMatchQuery(model.getKeyword(), "jp", "qp").analyzer("pinyin"));
            bool0.must(bool2);
        }

        // 前面两个条件都没有设置的时候，不set
        if (!CollectionUtils.isEmpty(bool0.must())) {
            searchSourceBuilder.query(bool0);
        }
        log.info("请求参数：" + searchSourceBuilder.toString());
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = esClusterClient.search(searchRequest, RequestOptions.DEFAULT);
            if (searchResponse.status().getStatus() == 200) {
                log.info("返回条数：" + searchResponse.getHits().getTotalHits());
                // 解析对象
                ResponseDto responseDto = JSONObject.parseObject(JSONObject.toJSONString(searchResponse.getHits()), ResponseDto.class);
                ResponseResultDto responseResultDto = new ResponseResultDto();
                responseResultDto.setTotal(responseDto.getTotalHits().getValue());
                List<SmartSearchDto> smartSearchDtoList = new ArrayList<>();
                for(ResponseHitsDto responseHitsDto : responseDto.getHits()) {
                    smartSearchDtoList.add(responseHitsDto.getSourceAsMap());
                }
                responseResultDto.setDatas(smartSearchDtoList);
                return responseResultDto;
            }
        } catch (IOException e) {
            log.error("es搜索[search]报错，", e);
        }
        return null;
    }

    @Override
    public ResponseEsDemoDto searchByEsDemo(SmartSearchModel model) {
        SearchRequest searchRequest = new SearchRequest("index-gs-eleven-poi");
        //构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // es 分页每页条数，默认15条
        Integer size = (model.getPageSize() == null || model.getPageSize() < 1) ? 15 : model.getPageSize();
        // es 分页起始行数，默认0行开始
        Integer from = (model.getPageIndex() == null || model.getPageIndex() <= 1) ? 0 : (model.getPageIndex() - 1) * size;
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);
        //设定希望返回的字段数组
        String[] fetchSourceArray = fetchSources.split(",");
        searchSourceBuilder.fetchSource(new String[]{"objectid","province","city","county","town","road_name","name","qp","jp","longitude","latitude","address"}, null);
        // 跟级bool查询
        BoolQueryBuilder bool0 = QueryBuilders.boolQuery();

        // 省市区等过滤bool查询
        BoolQueryBuilder bool1 = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(model.getCounty())) {
//            bool1.must(QueryBuilders.termQuery("road_name", model.getCounty()));
            bool1.must(QueryBuilders.termQuery("county", model.getCounty()));
            bool0.must(bool1);
        } else if (!StringUtils.isEmpty(model.getCity())) {
            bool1.must(QueryBuilders.termQuery("city", model.getCity()));
            bool0.must(bool1);
        } else if (!StringUtils.isEmpty(model.getProvince())) {
            bool1.must(QueryBuilders.termQuery("province", model.getProvince()));
            bool0.must(bool1);
        }

        // 名称、拼音、简拼、地址条件查询
        BoolQueryBuilder bool2 = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(model.getKeyword())) {
//            bool2.should(QueryBuilders.matchQuery("name", model.getKeyword()).analyzer("ik_smart"));
//            bool2.should(QueryBuilders.matchQuery("qp", model.getKeyword()).analyzer("pinyin"));
//            bool2.should(QueryBuilders.matchQuery("jp", model.getKeyword()).analyzer("pinyin"));
//            bool2.should(QueryBuilders.matchQuery("address", model.getKeyword()).analyzer("ik_smart"));
            bool2.should(QueryBuilders.multiMatchQuery(model.getKeyword(), "name", "address").analyzer("ik_smart"));
            bool2.should(QueryBuilders.multiMatchQuery(model.getKeyword(), "jp", "qp").analyzer("pinyin"));
            bool0.must(bool2);
        }

        // 前面两个条件都没有设置的时候，不set
        if (!CollectionUtils.isEmpty(bool0.must())) {
            searchSourceBuilder.query(bool0);
        }
        log.info("请求参数：" + searchSourceBuilder.toString());
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = esClusterClient.search(searchRequest, RequestOptions.DEFAULT);
            if (searchResponse.status().getStatus() == 200) {
                log.info("返回条数：" + searchResponse.getHits().getTotalHits());
//            Iterator<SearchHit> iterator = searchResponse.getHits().iterator();
//            while (iterator.hasNext()) {
//                log.info("输出数据:" + iterator.next().getSourceAsString());
//            }
                ResponseEsDemoDto responseDto = JSONObject.parseObject(JSONObject.toJSONString(searchResponse.getHits()), ResponseEsDemoDto.class);
                // 解析对象
                return responseDto;
            }
        } catch (IOException e) {
            log.error("es搜索[search]报错，", e);
        }
        return null;
    }

}
